#include "net/tcp_client.h"
#include "net/tcp_stream.h"
#include "net/buffer.h"
#include "net/socket.h"
#include "net/socket_opt.h"
#include "net/processor.h"

namespace net {
TcpClient::TcpClient(Poller* poller, const std::string& ip, uint16 port)
    : poller_(poller), ip_(ip), port_(port), need_reconnect_(false) {
  reconnect_closure_ = NULL;

  reconnect_thread_.reset(
      new StopableThread(
          NewMethordClosure0(this, &TcpClient::connect_monitor)));
}

TcpClient::~TcpClient() {
  reconnect_thread_.reset();
  stream_.reset();
  poller_.reset();
}

void TcpClient::SetProcessor(Processor* processor) {
  processor_.reset(processor);
}

bool TcpClient::Start() {
  if (!Connect()) {
    return false;
  }

  reconnect_thread_->Start();
  return true;
}

bool TcpClient::Connect() {
  scoped_ptr<Socket> socket(Socket::CreateSocket(sock::CreateSocket()));
  if (!socket->Connect(Addr(ip_, port_))) {
    return false;
  }

  stream_.reset(new TcpStream(socket.get(), poller_.get()));
  socket->SetBlock(false);
  stream_->SetProcessor(processor_.get());
  stream_->SetCloseClosure(
      NewMethordClosure0(this, &TcpClient::NotifyReconnect));
  if (!stream_->Init()) {
    return false;
  }
  socket.release();
  return true;
}

void TcpClient::NotifyReconnect() {
  ScopedMutex l(&reconnect_mutex_);
  need_reconnect_ = true;
}

void TcpClient::connect_monitor() {
  bool tmp_value;
  {
    ScopedMutex l(&reconnect_mutex_);
    tmp_value = need_reconnect_;
  }
  if (!tmp_value) {
    if (reconnect_cond_.TimeWait(1)) {
      return;
    }
  }

  if (Connect()) {
    ScopedMutex l(&reconnect_mutex_);
    need_reconnect_ = false;
  }
}
}
